using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using COC.Graphics;
using COC.GameLogic;
using WCamera;
using LuaNetInterface;


namespace COC
{
	/// <summary>
	/// This is a game component that implements IUpdateable.
	/// </summary>
	public class GameWorld : DrawableGameComponent
	{
		internal SkydomeComponent m_SkyDome;
		internal TerrainComponent m_Terrain;
		internal AnimComponent m_Animation;
		internal BillBoardComponent m_BillBoard;
		internal ShootDetecter m_ShootDetecter = new ShootDetecter();
		private readonly Random rand = new Random(System.DateTime.Now.Millisecond);

		PlayerActor m_Actor = null;
		Dictionary<string, PlayerActor> m_Mobs = new Dictionary<string, PlayerActor>();

		public GameWorld(Game game)
			: base(game)
		{
			// TODO: Construct any child components here
			m_SkyDome = new SkydomeComponent();
			m_Terrain = new TerrainComponent();
			m_Animation = new AnimComponent();
			m_BillBoard = new BillBoardComponent();
			this.Disposed += new EventHandler(GameWorld_Disposed);
		}

		[LuaFunctionAttribute("spawn", "", "name")]
		public void CreateMainCharacter(string name)
		{
			if (m_Actor != null)
				return;
			m_Actor = new PlayerActor(name, "PlayerMarine", 100, 10, 0.7f);
			m_Actor.SetWeapon("WeaponMachineGun");
		}

		[LuaFunctionAttribute("spawnMob", "", "name")]
		public void CreateMob(string name)
		{
			if (m_Mobs.ContainsKey(name))
			{
				CoCGame.Singleton.Console.WriteLine("Actor with the same name already exists.");
				return;
			}

			PlayerActor amob = new PlayerActor(name, "EnemyBeast", 50, 12, 0.3f);
			amob.Position = TerrainManager.Singleton.GetPositionByUV(
				new Vector2((float)rand.NextDouble(), (float)rand.NextDouble()));
			m_Mobs.Add(amob.Name, amob);

			m_ShootDetecter.AddActor(amob);
		}

		public void RemoveMob(string name)
		{
			m_Mobs.Remove(name);
			m_ShootDetecter.RemoveActor(name);
		}

		[LuaFunctionAttribute("spawnMany", "", "count")]
		public void SpawnManyCrabs(int count)
		{
			for(int i=0; i<count; i++)
			{
				CreateMob(i.ToString());
			}
		}

		[LuaFunctionAttribute("bind", "", "actorname")]
		public void BindCameraToActor(string actorname)
		{
			AnimActor actor = null;
			if (m_Actor != null && m_Actor.Name == actorname)
			{
				actor = m_Actor;
			}
			else
			{
				if (m_Mobs.ContainsKey(actorname))
				{
					actor = m_Mobs[actorname];
				}
			}
			if (actor == null)
				return;

			CameraUpdater.BindCameraToActor(CoCGame.Singleton.GameCamera, actor);
			CameraUpdater.UpdateCamera(
				CoCGame.Singleton.GameCamera, actor, new Vector2(0, m_RotY));
		}

		[LuaFunctionAttribute("setState", "", new string[] { "name", "state" })]
		public void SetActorState(string name, string state)
		{
			if (m_Actor != null && m_Actor.Name == name)
			{
				m_Actor.DoAction(state);
			}
			else if (m_Mobs.ContainsKey(name))
			{
				m_Mobs[name].DoAction(state);
			}
		}

		private float m_RotY = 0;

		public bool UpdateActor(Camera camera, float advanceVal, float sidemoveVal, Vector2 rotVal, bool isLBtnDown)
		{
			if (m_Actor == null)
				return false;

			Vector3 dir = m_Actor.Direction;
			Vector3 right = Vector3.Cross(dir, new Vector3(0, 1, 0));
			m_Actor.Position = m_Actor.Position + dir * advanceVal + right * sidemoveVal;
			m_Actor.Rotation += new Vector3(0, rotVal.X, 0);
			m_RotY += rotVal.Y;

			BindCameraToActor(m_Actor.Name);

			if ((Math.Abs(advanceVal) > float.Epsilon
				|| Math.Abs(sidemoveVal) > float.Epsilon)
				&& !isLBtnDown)
			{
				SetActorState(m_Actor.Name, "Run");
			}
			else if (isLBtnDown)
			{
				SetActorState(m_Actor.Name, "Shoot");
			}
			else
			{
				SetActorState(m_Actor.Name, "Idle");
			}
			return true;
		}

		/// <summary>
		/// Allows the game component to perform any initialization it needs to before starting
		/// to run.  This is where it can query for any required services and load content.
		/// </summary>
		public override void Initialize()
		{
			// TODO: Add your initialization code here
			m_SkyDome.Initialize();
			TerrainManager.Singleton.Initialize(2000, 2000, 5, 33, 256, "3.raw", "grass.jpg");
			m_Terrain.Initialize();
			m_Animation.Initialize();
			m_BillBoard.Initialize();
			base.Initialize();
		}

		/// <summary>
		/// Allows the game component to update itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		public override void Update(GameTime gameTime)
		{
			// TODO: Add your update code here

			base.Update(gameTime);
			if(m_Actor != null)
			{
				m_Actor.Update(gameTime);
			}

			List<PlayerActor> toRemove = new List<PlayerActor>();

			foreach(PlayerActor mob in m_Mobs.Values)
			{
				if(!mob.Update(gameTime))
				{
					toRemove.Add(mob);
				}
			}

			foreach (PlayerActor mob in toRemove)
			{
				m_Mobs.Remove(mob.Name);
			}
		}

		public override void Draw(GameTime gameTime)
		{


			m_SkyDome.Render();
			m_Terrain.Render();
			m_Animation.Render();
			m_BillBoard.Render();
			base.Draw(gameTime);
		}

		void GameWorld_Disposed(object sender, EventArgs e)
		{
			m_SkyDome.Dispose();
			TerrainManager.Singleton.Dispose();
			m_Terrain.Dispose();
			m_Animation.Dispose();
			m_BillBoard.Dispose();
		}
	}
}